ASP.NET MVC:動作內的授權 - 建議的模式或者這是一種氣味? (ASP.NET MVC: Authorization inside an Action - Suggested Patterns or this is a smell?)


問題描述

ASP.NET MVC:動作內的授權 ‑ 建議的模式或者這是一種氣味? (ASP.NET MVC: Authorization inside an Action ‑ Suggested Patterns or this is a smell?)

I have an ASP.NET MVC application using Authorization Attributes on Controllers and Actions.  This has been working well but a new wrinkle has shown up.

Object: Shipment

Roles: Shipping, Accounting, General User

The Shipment moves through a workflow.  In state A it can be edited by Shipping only.  In state B it can be edited by Accounting only.

I have a ShipmentController, and an Edit Action.  I can put an Authorization attribute to limit the Edit action to only those two roles, but this doesn't distinguish between which state the Shipment is in.  I would need to do some Authorization inside the action before the service call to determine if the user is really authorized to execute the edit action.

So I'm left with two questions:

1) Whats a good way to have authorization inside an Action.  The Controller Action calls to a service, and the service then makes appropriate calls to the Shipment object (update quantity, update date, etc).  I know for sure I want the Shipment object to be agnostic of any authorization requirements.  On the other hand, I don't have a real grasp if I would want the service object to know about authorization or not.  Are there any good patterns for this?

2) Is my problem actually a symptom of bad design?  Instead of ShipmentController should I have a StateAShipmentController and StateBShipmentController?  I don't have any polymorphism built into the Shipment object (the state is just an enum), but maybe I should and maybe the Controllers should reflect that.

I guess I'm after more general solutions, not a specific one for my case.  I just wanted to provide an example to illustrate the question.

Thanks!

‑‑‑‑‑

參考解法

方法 1:

I don't see a problem with an Action method doing further authorization checks within it. You can leverage the Roles provider for the fine‑grained authorization you're looking for. Please excuse my syntax here ‑ it's likely rough and I haven't tested this.

[Authorize(Roles="Shipping, Accounting")]
public ActionResult Edit(int id)
{
    Shipment shipment = repos.GetShipment(id);


    switch (shipment.State)
    {
         case ShipmentState.A:
         if (Roles.IsUserInRole("Shipping"))
                return View(shipment);
         else
                return View("NotAuthorized");
         break;
         case ShipmentState.B:
         if (Roles.IsUserInRole("Accounting"))
                return View(shipment);
         else
               return View("NotAuthorized");
         break;
         default:
              return View("NotAuthorized");
     }
}

方法 2:

Your authorization attribute could get the Shipment from action parameters or route data and then make a decision.  

For number 1, there are a number of patterns that enable rich behavior in domain objects.  In double‑dispatch, you pass a reference to a service abstraction (interface) to a method on the object.  Then it can do its thing.  You can also write an application service that takes the Shipment and does the work.

On number 2, not necessarily.  You may need to abstract the concept of a "contextual Shipment" into a service that figures out which Shipment context you're in.  But I'd YAGNI that until you need it again.

方法 3:

You could take a look at Rhino.Security, it could be used to implement user authorization in these kinds of scenarios. 

方法 4:

In addition to the answer above, you can return a HttpUnauthorizedResult instead of creating your own view for NotAuthorized. This will redirect to the login page and behave just like the usual [Authorize] attribute

(by anonymousJosh EMatt HinzeIgor Brejcchris166)

參考文件

  1. ASP.NET MVC: Authorization inside an Action ‑ Suggested Patterns or this is a smell? (CC BY‑SA 3.0/4.0)

#authorization #single-responsibility-principle #model-view-controller #design-patterns #asp.net-mvc






相關問題

如何從 Flex WebService 傳遞授權標頭? (How to pass Authorization header from Flex WebService?)

使用 socket.io 授權 (authorization with socket.io)

Rails CanCan 只有當前用戶可以通過編輯 (Rails CanCan only current user can go through Edit)

Ruby HTTP 發送 API 密鑰 Basic_auth (Ruby HTTP sending API key Basic_auth)

如何在 symfony 中創建自定義記住我的提供程序 (How to create custom Remember me provider in symfony)

永無止境的故事:Twitter 身份驗證 (Never Ending Story: Twitter Authentication)

有沒有標準的asp.net認證授權登錄系統? (Is there a standard asp.net authentication authorization login system?)

ASP.NET MVC:動作內的授權 - 建議的模式或者這是一種氣味? (ASP.NET MVC: Authorization inside an Action - Suggested Patterns or this is a smell?)

ASP.NET MVC 授權和超鏈接 (ASP.NET MVC Authorization and hyperlinks)

$.ajax 中的某些參數未通過 (Some Parameters in $.ajax not passing)

如何:(jQuery) 帶有 ASP.NET MVC 2 的模態登錄對話框? (How to: (jQuery) Modal login dialog w/ ASP.NET MVC 2?)

如何通過api網關將標頭中的cognito身份驗證令牌傳遞給lambda函數 (How to pass cognito authentication token in the headers through api gateway to a lambda function)







留言討論